﻿using YL.NetCore.NetCoreApp;
using Microsoft.AspNetCore.Mvc;
using System.Security.Claims;
using System.Threading.Tasks;
using YL.Core.Dto;
using IServices;
using System.Text;
using System.IdentityModel.Tokens.Jwt;
using System;
using YL.Utils.Security;
using MediatR;
using YL.Core.Entity;
using YL.Utils.Pub;
using YL.Utils.Table;
using Microsoft.IdentityModel.Tokens;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using System.Security.Cryptography;
using AngleSharp.Io;
using System.Linq;
using YL.Utils.Extensions;
using NPOI.OpenXmlFormats.Vml;
using Microsoft.Extensions.Logging;
using YL.Utils.String;

namespace EduCMS.Controllers
{
    [Route("[controller]")]
    public class LoginController : BaseController 
    {

        private readonly IWhr_wechat_sessionServices _services;
        private readonly IWhr_user_refresh_tokenServices _userRefreshTokenServices;

        public LoginController(
            IWhr_wechat_sessionServices services,
            IWhr_user_refresh_tokenServices user_Refresh_TokenServices           
            ) 
        {
            _services = services;
            _userRefreshTokenServices = user_Refresh_TokenServices;            
        }

        /// <summary>
        /// 生成访问令牌
        /// </summary>
        /// <param name="claims"></param>
        /// <returns></returns>
        private string GenerateAccessToken(Claim[] claims)
        {
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(PubConst.SecurityKey));
            var token = new JwtSecurityToken(
                    issuer: GetHost(),
                    audience: GetHost(),
                    claims: claims,
                    notBefore: DateTime.Now,
                    expires: DateTime.Now.AddHours(2),
                    signingCredentials: new SigningCredentials(key, SecurityAlgorithms.HmacSha256)
                );
            return new JwtSecurityTokenHandler().WriteToken(token);
        }       

        /// <summary>
        /// 从Token中获取用户身份，不验证是否过期的
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        private ClaimsPrincipal GetClaimsPrincipalFromAccessToken(string token) 
        {
            var handler = new JwtSecurityTokenHandler();

            try
            {
                return handler.ValidateToken(token, new TokenValidationParameters
                {
                    ValidateAudience = false,
                    ValidateIssuer = false,
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(PubConst.SecurityKey)),
                    ValidateLifetime = false
                }, out SecurityToken validatedToken);
            }
            catch (Exception) 
            {
                return null;
            }
        }

        //login/refresh_token
        [HttpPost("refresh_token")]
        [AllowAnonymous]
        public IActionResult RefreshToken([FromForm]TokenDto request) 
        {
            //从过期老jwt中获取用户信息
            var principal = GetClaimsPrincipalFromAccessToken(request.AccessToken);
            if (principal is null) 
            {
                return Json(Microprogram.DataInfo(PubEnum.Failed, "token为空", null));
            }
            var id = principal.Claims.First(c => c.Type == JwtRegisteredClaimNames.Sub).Value;
            if (id is null) 
            {
                return Json(Microprogram.DataInfo(PubEnum.Failed, "token为空", null));
            }
            var isValid = _userRefreshTokenServices.IsValidRefreshToken(request.RefreshToken);
            if (!isValid) 
            {
                return Json(Microprogram.DataInfo(PubEnum.Failed, "refresh_token无效", null));
            }
            //删除refresh_token
            var removed = _userRefreshTokenServices.RemoveRefreshToken(request.RefreshToken);
            if (!removed) 
            {
                return Json(Microprogram.DataInfo(PubEnum.Failed, "删除refresh_token失败", null));
            }
            var refreshToken = StringHelper.GenerateRefreshToken();

            var writeToken = _userRefreshTokenServices.CreateRefreshToken(refreshToken, id.ToInt32());

            var user = _services.QueryableToEntity(d => d.Id == id.ToInt32());

            if (user is null) 
            {
                return Json(Microprogram.DataInfo(PubEnum.Failed, "用户信息有误", null));
            }

            var claims = new Claim[]
                {
                    new Claim(ClaimTypes.Name, user.Nickname),
                    new Claim(JwtRegisteredClaimNames.Sub, user.Id.ToString()),
                    new Claim(JwtRegisteredClaimNames.Exp,  $"{new DateTimeOffset(DateTime.Now.AddHours(3)).ToUnixTimeSeconds()}"),
                    new Claim(JwtRegisteredClaimNames.Nbf, $"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}")
                };
            var jwtToken = GenerateAccessToken(claims);

            return Json(Microprogram.DataInfo(new { token = jwtToken, refresh_token = refreshToken }, (int)HttpResultCode.Success));
        }
    }
}